package com.icehelper.hades.base.log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.message.Message;
import org.slf4j.MDC;

/**
 * @author Leon Sun
 */
public class HadesLogEventFactory implements LogEventFactory {

  private static final ThreadLocal<Map<String, String>> KV_HOLDER =
      ThreadLocal.withInitial(HashMap::new);

  /**
   * Creates a log event.
   *
   * @param loggerName The name of the Logger.
   * @param marker An optional Marker.
   * @param fqcn The fully qualified class name of the caller.
   * @param level The event Level.
   * @param data The Message.
   * @param properties Properties to be added to the log event.
   * @param t An optional Throwable.
   * @return The LogEvent.
   */
  @Override
  public LogEvent createEvent(final String loggerName, final Marker marker,
      final String fqcn, final Level level, final Message data,
      final List<Property> properties, final Throwable t) {
    List<Property> finalProperties = properties == null ? new ArrayList<>() : properties;
    KV_HOLDER.get().forEach((k, v) -> finalProperties.add(Property.createProperty(k, v)));

    Map<String, String> mdcMap = MDC.getCopyOfContextMap();
    for (Map.Entry<String, String> entry : mdcMap.entrySet()) {
      String k = entry.getKey();
      String v = entry.getValue();

      //如果自己的threadlocal里面没有，在添加
      if (StringUtils.isBlank(KV_HOLDER.get().get(k))) {
        finalProperties.add(Property.createProperty(k, v));
      }

      //删除MDC中的数据，仅仅保留traceId 和 spanId
      if (!k.equals(LogConstant.KEY_TRACE_ID) && !k.equals(LogConstant.KEY_SPAN_ID)) {
        MDC.remove(k);
      }

    }

    KV_HOLDER.get().clear();

    return new HadesLogEvent(loggerName, marker, fqcn, level, data, finalProperties, t);
  }

  static void setKv(String key, String value) {
    KV_HOLDER.get().put(key, value);
  }
}
